/*
 * Hal_CAN.c
 *
 *  Created on: Jul 5, 2023
 *      Author: work
 */

#include "hal_can.h"
#include "can_signal.h"
static func    hal_func_cbk;
static recv_func hal_recv_func_cbk;

static CANConfig config;
static CANDriver *cand;
static HAL_CAN_TRCV_ModeTypeDef CAN_TRCV_Mode;
static volatile CANReg *reg = NULL;
extern CANIntrCallback g_intr_callback[CAN_MOD_BUTT];
static volatile CANReg* Can_LLD_Get_Reg_t_hal(can_channel channel);
uint32_t Can_LLD_Send_Msg_hal(can_channel channel, const CANTxMsg *tx_msg, uint32_t *msg_id);
uint32_t hal_can_read(can_channel channel,CANRxMsg *rx_msg);
static uint8_t can_busoff_flag;
/*
 * function description: Fifo_Recv_Msg_Callback
 * param: CANDriver *drv, CANRxMsg * rx_msg
 * return: void 
 * TODO:
*/
static void hal_Fifo_Recv_Msg_Callback(CANDriver *drv, CANRxMsg * rx_msg) /* PRQA S 3673 */
{
    pdu_str pdu_str_rxmsg;
    uint8_t g_fifo_recv_msg_ok = FALSE; /* PRQA S 1504 */
    int i = 0;
    // if (drv->id != CAN_MOD_ID_1)
    // {
    //     return ;
    // }
    // if (rx_msg->data.word[0] != 0x5a5a5a5aU)
    // {
    //     return ;
    // }
    can_rx_Msg_Callback(rx_msg->data.byte);
    hal_can_read(drv->id,rx_msg);
    pdu_str_rxmsg.ID = rx_msg->id;
    for (i = 0; i < rx_msg->data_len; i++)
    {
        pdu_str_rxmsg.buff[i] = &(rx_msg->data.byte[i]);
    }
    pdu_str_rxmsg.DLC = rx_msg->data_len;
    pdu_str_rxmsg.id_type = rx_msg->is_extern;
    if (NULL != hal_recv_func_cbk)
    {
        hal_recv_func_cbk(&pdu_str_rxmsg);
    }
    g_fifo_recv_msg_ok = TRUE;
}
/*
 * function description: Can busoff interrupt callback function
 * param: CANDriver *drv
 * return: void 
 * TODO:
*/
 void hal_busoff_Callback(CANDriver *drv) /* PRQA S 3673 */
{
	uint8_t tx_error_cnt = 0;
	uint8_t rx_error_cnt = 0;
    uint8_t g_fifo_recv_msg_ok = FALSE; /* PRQA S 1504 */
    can_busoff_flag = 1;
    if (drv->id != CAN_MOD_ID_0)
    {
        return ;
    }
    if (NULL != hal_func_cbk)
    {
        hal_func_cbk();
    }
    tx_error_cnt = hal_can_TEC(drv->id);
    rx_error_cnt = hal_can_REC(drv->id);
    g_fifo_recv_msg_ok = TRUE;
}

/*
 * function description: This function shall be set buffer value.
 * param: uint8_t * dest, uint8_t val, uint32_t bytes
 * return: void 
 * TODO:
*/
void hal_cc_memset(uint8_t * dest, uint8_t val, uint32_t bytes)
{
    uint32_t bytes_temp;
    uint8_t  * dest_temp = NULL;

    dest_temp = dest;
    //bytes_temp = bytes;

    //  while (bytes_temp > 0u)
    //  {
    //      *dest_temp = val;
    //      bytes_temp--;
    //      if (0u == bytes_temp)
    //      {
    //          break;
    //      }
    //      dest_temp++;
    //  }
   for (bytes_temp = bytes; bytes_temp <= 0u; bytes_temp--)
   {
       *dest_temp = val;
       dest_temp++;
   }
    
}
/*
 * function description: Deinitializes the CAN peripheral.
 * param: CANDriver *cand
 * return: uint32_t 
 * TODO:
*/
static uint32_t hal_Can_LLD_DeInit(CANDriver *cand)
{
    volatile CANReg *reg = NULL;
    uint8_t i;
    if (cand->state.cur_mode == CAN_CUR_MODE_INIT)
    {
        return CAN_ERROR_INVALID_STATE;
    }
    /* fetch register */
    reg = Can_LLD_Get_Reg_t_hal(cand->id);
    /* configure soft reset */
    reg->MCR.B.SOFTRST = ENABLE;
    // while (reg->MCR.B.SOFTRST == ENABLE)
    // {
    //     ;
    // }
    for ( i = 0; i < HAL_CAN_WAIT; i++)
    {
        if (reg->MCR.B.SOFTRST != ENABLE)
        {
            break;
        }
        
    }
    
    /* sisable self-loopback */
    reg->CR.B.LPB = DISABLE;
    /* globally disable */
    reg->MCR.B.MDIS = ENABLE; /* set MDIS 1 */
    /* disable clock */
    Can_LLD_Config_Clock(cand->id, DISABLE);
    /* clean handle */
    cc_memset((uint8_t *)cand, 0, sizeof(CANDriver));
    /* update status */
    cand->state.cur_mode = CAN_CUR_MODE_INIT;

    return CAN_OK;
}
/*
 * function description: Initialize CAN configuration
 * param: can_channel channel,str * hal_str
 * return: uint32_t 
 * TODO:
*/
uint32_t hal_can_init(can_channel channel,str * hal_str)
{
    uint32_t ret = CAN_OK;
    can_busoff_flag = 0;
    INTC.CPR.B.PRI = 0;
    hal_cc_memset((uint8_t *)&config, 0, sizeof(config));
    hal_cc_memset((uint8_t *)&cand, 0, sizeof(cand));
    
    reg = Can_LLD_Get_Reg_t_hal(channel);
    /* STEP1 Set initialization parameters */
    config.phy_para.use_bus_clk_src = TRUE;
    config.phy_para.bit_rate = hal_str->arbitr;//CAN_KBPS_500
    config.func_switch.fifo_en = TRUE;
    config.func_switch.loop_back_en = FALSE;
    config.fifo[0].is_remote = FALSE;
    config.fifo[0].is_extern = FALSE;
    config.fifo[0].id = 0x11;
    config.fifo[0].mask = 0xffffffffU;
    config.call_back.rx_fifo_msg_received = hal_Fifo_Recv_Msg_Callback;
    config.call_back.busoff = hal_busoff_Callback;
    config.can_id = channel;
    (void)hal_Can_LLD_DeInit(Can_LLD_Get_Driver((CANModId)config.can_id)); /* PRQA S 4342 */
    /* check configuration */
    ret = Can_LLD_Cfg_Check(&config);
    if(ret != CAN_OK)
    {
        return ret;
    }
    /* mount descriptor */
    cand = Can_LLD_Get_Driver(config.can_id);
    (cand)->id = config.can_id;
    /* check status */
    if ((cand)->state.cur_mode != CAN_CUR_MODE_INIT)
    {
        return CAN_ERROR_INVALID_STATE;
    }
        /* mapped port */
    Can_LLD_Init_Port((cand)->id);
    hal_can_enabled(channel,hal_str->canenabled);
	hal_can_baudrate(channel,hal_str->arbitr);
}

/*
 * function description: Switches the system to the specified run mode.
 * param: uint8_t mode
 * return: uint8_t 
 * TODO:
*/
uint8_t hal_SetRunMode(uint8_t mode) /* PRQA S 1505*/
{
    int i;
    /* Clearing status register bits */
    ME.IS.R = 0xFU;

    /* Starts a transition process.*/
    ME.MCTL.R = ME_MCTL_MODE(mode) | ME_MCTL_KEY;       /* PRQA S 3469*/
    ME.MCTL.R = ME_MCTL_MODE(mode) | ME_MCTL_KEY_INV;   /* PRQA S 3469*/

    /* Waits for the mode switch or an error condition.*/
    // while (ME.IS.R == 0U)
    // {
    //     ;
    // }
    for (i = 0; i < 1000; i++)
    {
        if(ME.IS.R != 0U) break;
    }
    

    /* Check if no error during mode switch */
    if (ME.IS.B.I_MTC == 1U)
    {
        return CLOCK_SUCCESS;
    }
    else
    {
        return CLOCK_FAILED;
    }
}

/*
 * function description: Changes the clock mode of a peripheral
 * param: uint32_t n, uint32_t pctl
 * return: void 
 * TODO:
*/
void hai_SetPeripheralClockMode(uint32_t n, uint32_t pctl)
{
    uint8_t mode;

    ME.PCTL[n].R = (uint8_t)pctl;
    mode = (uint8_t)ME.MCTL.B.TARGET_MODE;

    if (hal_SetRunMode(mode) == CLOCK_FAILED)
    {
        CLOCK_FAILURE_HOOK(); /* PRQA S 3469*/
    }
}
/*
 * function description: can_enabled
 * param: can_channel channel,can_enabled is_enable
 * return: void 
 * TODO:
*/
void hal_can_enabled(can_channel channel,can_enabled is_enable)
{
    /* enable clock */
	static const struct
	    {
	        uint32_t reg_idx;
	        uint32_t reg_val;
	    } enable_cfg[CAN_MOD_BUTT] =
	    {
	        {16, CAN_FLEXCAN0_START_PCTL}, // CAN_MOD_ID_0,
	        {17, CAN_FLEXCAN1_START_PCTL}, // CAN_MOD_ID_1,
	        {18, CAN_FLEXCAN2_START_PCTL}, // CAN_MOD_ID_2,
	        {19, CAN_FLEXCAN3_START_PCTL}, // CAN_MOD_ID_3,
	        {20, CAN_FLEXCAN4_START_PCTL}, // CAN_MOD_ID_4,
	        {21, CAN_FLEXCAN5_START_PCTL}, // CAN_MOD_ID_5,
	    }, disable_cfg[CAN_MOD_BUTT] =
	    {
	        {16, CAN_FLEXCAN0_STOP_PCTL}, // CAN_MOD_ID_0,
	        {17, CAN_FLEXCAN0_STOP_PCTL}, // CAN_MOD_ID_1,
	        {18, CAN_FLEXCAN0_STOP_PCTL}, // CAN_MOD_ID_2,
	        {19, CAN_FLEXCAN0_STOP_PCTL}, // CAN_MOD_ID_3,
	        {20, CAN_FLEXCAN0_STOP_PCTL}, // CAN_MOD_ID_4,
	        {21, CAN_FLEXCAN0_STOP_PCTL}, // CAN_MOD_ID_5,
	    };
	cand->id = channel;
    //Can_LLD_Config_Clock(cand->id, CAN_ENABLE);
    
    if (is_enable != 0U)
    {
        hai_SetPeripheralClockMode(enable_cfg[channel].reg_idx,
            enable_cfg[channel].reg_val);
    }
    else
    {
        hai_SetPeripheralClockMode(disable_cfg[channel].reg_idx,
            disable_cfg[channel].reg_val);
    }
    reg->CR.B.CLKSRC = (config.phy_para.use_bus_clk_src);
    /* global enable */
    reg->MCR.B.MDIS = DISABLE; /* set MDIS 0 */

    
}

/*
 * function description: Obtain CAN register
 * param: can_channel channel
 * return: CANReg* 
 * TODO:
*/
static volatile CANReg* Can_LLD_Get_Reg_t_hal(can_channel channel)
{
    static volatile CANReg * const regG[CAN_MOD_BUTT] =
    {
        (volatile CANReg*)&CAN_0,
        (volatile CANReg*)&CAN_1,
        (volatile CANReg*)&CAN_2,
        (volatile CANReg*)&CAN_3,
        (volatile CANReg*)&CAN_4,
        (volatile CANReg*)&CAN_5,
    };
    return regG[channel];
}
/*
 * function description: CAN recv interrupt callback configuration function
 * param: can_channel channel ,recv_func recv_func_cbk
 * return: void 
 * TODO:
*/
void hal_can_recv_cbk(can_channel channel ,recv_func recv_func_cbk )
{
	config.can_id = channel;
    hal_recv_func_cbk = recv_func_cbk;
}
/*
 * function description: CAN BUSOF interrupt callback configuration function
 * param: can_channel channel ,func func_cbk
 * return: void 
 * TODO:
*/
void hal_busoff_cbk(can_channel channel ,func func_cbk)
{
	config.can_id = channel;
    hal_func_cbk = func_cbk;
}

/*
 * function description: set CAN baudrate
 * param: can_channel channel,CANBitRate baudrate
 * return: void 
 * TODO:
*/
static void hal_can_baudrate(can_channel channel,CANBitRate baudrate)
{
    uint8_t bit_rate = (uint8_t)baudrate;
    //btr = canclk/(PRESDIV+1)/(1+(PROPSEG+PSEG1+2)+(PSEG2+1))
    //Sampling points    = (1+(PROPSEG+PSEG1+2)+(PSEG2+1)) / (1+(PROPSEG+PSEG1+2)+(PSEG2+1)+RJW)
    static const CANTimeSeg time_seg_hal[6] ={
        {1, 2, 1, 3, 7},//CAN_MBPS_1
        {2, 2, 2, 3, 7},//CAN_KBPS_800
        {1, 2, 1, 3, 15},//CAN_KBPS_500 64M:{1, 2, 1, 3, 15},
        {1, 2, 1, 3, 31},//CAN_KBPS_250
        {1, 2, 1, 3, 63},//CAN_KBPS_125
        {2, 2, 2, 3, 63},//CAN_KBPS_100
    };
    config.can_id = channel;
    
    reg->CR.B.PROPSEG = time_seg_hal[bit_rate].prop_seg;
    reg->CR.B.PSEG1 = time_seg_hal[bit_rate].time_seg1;
    reg->CR.B.PSEG2 = time_seg_hal[bit_rate].time_seg2;
    reg->CR.B.RJW = time_seg_hal[bit_rate].rjw;
    reg->CR.B.PRESDIV = time_seg_hal[bit_rate].pres_div;
    reg->CR.B.TSYN = ENABLE;

    /* alloc mailbox */
    reg->MCR.B.MAXMB = CAN_TOTAL_MAIL_BOX_NUM - 1U;
}
/*
 * function description: set CAN tq
 * param: can_channel channel,uint8_t prop_seg,uint8_t seg1,uint8_t seg2,uint8_t sjw,uint8_t brp
 * return: void 
 * TODO:
*/
void hal_can_tq(can_channel channel,uint8_t prop_seg,uint8_t seg1,uint8_t seg2,uint8_t sjw,uint8_t brp)
{
	config.can_id = channel;
    reg->CR.B.PROPSEG = prop_seg;
    reg->CR.B.PSEG1 = seg1;
    reg->CR.B.PSEG2 = seg2;
    reg->CR.B.RJW = sjw;
    reg->CR.B.PRESDIV = brp;
    reg->CR.B.TSYN = ENABLE;
}

#if 0
void hal_can_filter_config(can_channel channel,CANFilter can_filter_array,uint16_t len)
{
	config.can_id = channel;
    /* init TX MB */
    Can_LLD_Init_Tx_MB(reg, &config);
    /* init RX MB */
    Can_LLD_Init_Rx_MB(reg, &config);

    config.fifo[0].is_remote = can_filter_array.is_remote;
    config.fifo[0].is_extern = can_filter_array.is_extern;
    config.fifo[0].id = can_filter_array.id;
    config.fifo[0].mask = can_filter_array.mask;
    Can_LLD_Init_Rx_FIFO(reg, &config);

    hal_can_irq_config(channel,IRQ_TYPE_RX_BUSOFF,CPR_PRI_11,CAN_ENABLE);
    /* select mode */
    Can_LLD_Select_Run_Mode(cand, reg, &config);

    /* Clear error code */
    reg->ECR.R = 0;
    reg->ESR.R = 0;
    /* start running */
    reg->MCR.B.HALT = DISABLE;
    reg->MCR.B.FRZ = DISABLE;
}
#endif
/*
 * function description: CAN filter configuration
 * param: can_channel channel,filter_struct can_filter_array[],uint16_t len
 * return: void 
 * TODO:
*/
void hal_can_filter_config(can_channel channel,filter_struct can_filter_array[],uint16_t len)
{
    uint8_t i = 0;
	config.can_id = channel;
    /* init TX MB */
    Can_LLD_Init_Tx_MB(reg, &config);
    /* init RX MB */
    Can_LLD_Init_Rx_MB(reg, &config);
    // config.fifo[0].is_remote = can_filter_array.is_remote;
    // config.fifo[0].is_extern = can_filter_array.is_extern;
    // config.fifo[0].id = can_filter_array.id;
    // config.fifo[0].mask = can_filter_array.mask;
    #if 0
    config.fifo[0].is_remote = FALSE;//When is_ When remote is a non-zero value, it indicates that the message is a remote frame; When is_ When remote is zero, it indicates that the message is a data frame
    config.fifo[0].is_extern = can_filter_array[len-1].id_type;//When is_ When extern is a non-zero value, it indicates that the message is an extended identifier frame; When is_ When extern is zero, it indicates that the message is a standard identifier frame.
    config.fifo[0].id = can_filter_array[len-1].filter_code;
    config.fifo[0].mask = can_filter_array[len-1].filter_mask;
    #else
    for (i; i < len; i++)
    {
        config.fifo[i].is_remote = FALSE;//When is_ When remote is a non-zero value, it indicates that the message is a remote frame; When is_ When remote is zero, it indicates that the message is a data frame
        config.fifo[i].is_extern = can_filter_array[i].id_type;//When is_ When extern is a non-zero value, it indicates that the message is an extended identifier frame; When is_ When extern is zero, it indicates that the message is a standard identifier frame.
        config.fifo[i].id = can_filter_array[i].filter_code;
        config.fifo[i].mask = can_filter_array[i].filter_mask;
    }
    #endif
    Can_LLD_Init_Rx_FIFO(reg, &config);

    hal_can_irq_config(channel,IRQ_TYPE_RX_BUSOFF,CPR_PRI_11,CAN_ENABLE);
    /* select mode */
    Can_LLD_Select_Run_Mode(cand, reg, &config);

    /* Clear error code */
    reg->ECR.R = 0;
    reg->ESR.R = 0;
    /* start running */
    reg->MCR.B.HALT = DISABLE;
    reg->MCR.B.FRZ = DISABLE;
}

/*
 * function description: Lauch an CAN frame transmission requests.
 * param: can_channel channel, const CANTxMsg *tx_msg, uint32_t *msg_id
 * return: uint32_t 
 * TODO:
*/
uint32_t Can_LLD_Send_Msg_hal(can_channel channel, const CANTxMsg *tx_msg, uint32_t *msg_id)
{

    CANModId can_id = channel;
    uint32_t mb_idx;

    /* alloc MB */
    mb_idx = Can_LLD_Alloc_Tx_MB(can_id);
    if (mb_idx >= CAN_TOTAL_MAIL_BOX_NUM)
    {
        return CAN_ERROR_MAIL_BOX_ALLOC;
    }


    /* check mailbox */
    if (reg->BUF[mb_idx].CS.B.CODE != CAN_TX_MB_STATE_INACTIVE)
    {
        /* The mailbox is not released here to avoid being assigned again */
        return CAN_ERROR_MAIL_BOX_STATE;
    }

    /* Fill in an email */
    if (tx_msg->is_extern != 0U)
    {
        reg->BUF[mb_idx].ID.R = 0;
        reg->BUF[mb_idx].ID.R |= (tx_msg->id & 0x1FFFFFFFU); /* extern ID */
    }
    else
    {
        reg->BUF[mb_idx].ID.B.STD_ID = tx_msg->id;
    }
    reg->BUF[mb_idx].ID.B.PRIO = tx_msg->local_prior;
    reg->BUF[mb_idx].DATA.W[0] = tx_msg->data.word[0];
    reg->BUF[mb_idx].DATA.W[1] = tx_msg->data.word[1];
    reg->BUF[mb_idx].CS.B.IDE = tx_msg->is_extern;
    reg->BUF[mb_idx].CS.B.RTR = tx_msg->is_remote;
    reg->BUF[mb_idx].CS.B.LENGTH = tx_msg->data_len;

    /* send mail */
    reg->BUF[mb_idx].CS.B.CODE = CAN_TX_MB_STATE_START_TRANS_DATA_MSG;

    /* Feedback message ID */
    *msg_id = Can_LLD_Bind_Msg_Id_To_MB(can_id, mb_idx);

    return CAN_OK;
}
/*
 * function description: Check if a transmission is finished.
 * param: can_channel channel, uint32_t msg_id
 * return: uint8_t 
 * TODO:
*/
uint8_t Can_LLD_Is_Msg_Transferred_hal(can_channel channel, uint32_t msg_id)
{
    uint32_t mb_idx;
    CANModId can_id = channel;

    for (mb_idx = 0; mb_idx < CAN_TOTAL_MAIL_BOX_NUM; mb_idx++)
    {
        if (msg_id == Can_LLD_Get_Msg_Id_From_MB(can_id, mb_idx))
        {
            break;
        }
    }
    if (mb_idx == CAN_TOTAL_MAIL_BOX_NUM)
    {
        return TRUE;
    }

    return FALSE;
}
/*
 * function description: Sending CAN data frames
 * param: can_channel channel,pdu_str * pdu
 * return: uint32_t 
 * TODO:
*/
uint32_t hal_can_write(can_channel channel,pdu_str * pdu)//uint8_t buff[],uint32_t id,uint32_t DLC
{
    if (NULL != pdu)
    {
        CANTxMsg tx_msg;
        uint32_t msg_id;
        uint32_t ret;
        uint8_t i = 0;
        /* STEP3 send message */
        tx_msg.is_remote = FALSE;
        tx_msg.is_extern = FALSE;
        tx_msg.data_len = pdu->DLC; //8
        tx_msg.id = pdu->ID; //0x11
        for (i=0; i < tx_msg.data_len; i++)
        {
            tx_msg.data.byte[i] = *(pdu->buff[i]);
        }
        ret = Can_LLD_Send_Msg_hal(channel, &tx_msg, &msg_id);
        if (ret != CAN_OK)
        {
            return ret;
        }
        // while (Can_LLD_Is_Msg_Transferred_hal(channel, msg_id) == FALSE)
        // {
        //     ;
        // }
//        for ( i = 0; i < HAL_CAN_WAIT; i++)
//        {
//             if (Can_LLD_Is_Msg_Transferred_hal(channel, msg_id) != FALSE)
//            {
//                break;/* code */
//            }
//        }
        
       
        
        return ret;
    }
    else
    {

    }
}
/*
 * function description: Get an CAN frame from Rx FIFO.
 * param: can_channel channel, CANRxMsg *rx_msg
 * return: uint32_t 
 * TODO:
*/
uint32_t Can_LLD_Recv_Msg_From_FIFO_hal(can_channel channel, CANRxMsg *rx_msg)
{

    volatile uint32_t rx_flag;

    config.can_id = channel;
    /* check FIFO */
    rx_flag = reg->IFRL.B.BUF05I; /* BUF5I indicate Frames available in FIFO */
    if (rx_flag == 0U)
    {
        return CAN_ERROR_FIFO_EMPTY;
    }
    /* read message */
    Can_LLD_Get_Buf_In_FIFO(reg, rx_msg);

    /* release message */ /* Write-clear */
    reg->IFRL.R = (1UL << 5UL);

    return CAN_OK;
}
/*
 * function description: Accept CAN data
 * param: can_channel channel,CANRxMsg *rx_msg
 * return: uint32_t 
 * TODO:
*/
uint32_t hal_can_read(can_channel channel,CANRxMsg *rx_msg)
{
    uint32_t ret;
    if (NULL != rx_msg)
    {
        ret = Can_LLD_Recv_Msg_From_FIFO_hal(channel, rx_msg);
        if (CAN_OK  != ret)
        {
            return ret;
        }
        // if (rx_msg.data.word[0] != 0x5a5a5a5aU)
        // {
        //     return CAN_ERROR_INVALID_MESSAGE;
        // }
        return ret;
    }
    else{

    }
}
/*
 * function description: set CAN transceiver mode
 * param: can_channel channel, HAL_CAN_TRCV_ModeTypeDef mode
 * return: void 
 * TODO:
*/
void hal_can_trcv_mode(can_channel channel, HAL_CAN_TRCV_ModeTypeDef mode) {

	config.can_id = channel;
    SIUL_Init_GPIO_Out((uint8_t)PC10_PCR, PCR_GPIO_OUT_PP);   /* PC[6], Open Drain Output Disable */
    CAN_TRCV_Mode = mode;
    SIUL_GPIO_OutputWrite((uint8_t)PC10_PCR, CAN_TRCV_Mode);

}
/*
 * function description: Obtain CAN transceiver mode
 * param: can_channel channel
 * return: HAL_CAN_TRCV_ModeTypeDef 
 * TODO:
*/
HAL_CAN_TRCV_ModeTypeDef hal_can_get_trcv_mode(can_channel channel) {
    HAL_CAN_TRCV_ModeTypeDef mode = CAN_TRCV_Mode;
    config.can_id = channel;
    return mode;
}

/*
 * function description: enter to sleep mode.
 * param: CANDriver * cand
 * return: void 
 * TODO:
*/
void hal_Can_LLD_Sleep(CANDriver * cand)
{
    //volatile CANReg *reg = NULL;

    /* fetch register */
    //reg = Can_LLD_Get_Reg(cand->id);
    /* global disable */
    reg->MCR.B.MDIS = ENABLE; /* set MDIS 1 */
    /* Wait feedback */
    while (reg->MCR.B.LPMACK == DISABLE)
    {
        ;
    }
    /* update status */
    cand->state.cur_mode = CAN_CUR_MODE_SLEEP;
}

/*
 * function description: Set CAN mode
 * param: can_channel channel,ControllerModeType ctrl_mode
 * return: void 
 * TODO:
*/
void hal_can_ctrl_mode(can_channel channel,ControllerModeType ctrl_mode)
{
	config.can_id = channel;
    if (CONTROLLERMODE_UNINIT == ctrl_mode)
    {
        cand->state.cur_mode = CAN_CUR_MODE_FREEZE;
    }
    else if (CONTROLLERMODE_STOPPED == ctrl_mode)
    {
        reg->MCR.B.MDIS = 1;
        cand->state.cur_mode = CAN_CUR_MODE_FREEZE;
    }else if (CONTROLLERMODE_STARTED == ctrl_mode)
    {
        reg->ECR.B.TXECNT = 0u;
        reg->MCR.B.HALT = 0u;
        reg->MCR.B.MDIS = 0u;
        cand->state.cur_mode = CAN_CUR_MODE_NORMAL;
    }else if (CONTROLLERMODE_SLEEP == ctrl_mode)
    {
        hal_Can_LLD_Sleep(cand);
    }else if (CONTROLLERMODE_BUSOFF == ctrl_mode)
    {
        reg->MCR.B.HALT = ENABLE;
        reg->MCR.B.FRZ = ENABLE;
        reg->ECR.B.TXECNT += 256u;
        //reg->ECR.B.TXECNT += 1u;
        cand->state.cur_mode = CAN_CUR_MODE_FREEZE;
    }else{}
    
}
/*
 * function description: Obtain the current mode of CAN
 * param: can_channel channel
 * return: ControllerModeType 
 * TODO:
*/
ControllerModeType hal_can_get_ctrl_mode(can_channel channel)
{
	volatile ControllerModeType ControllerMode;
    volatile uint32_t  hal_BOFFINT_T;
	static volatile  uint32_t* hal_BOFFINT;
	config.can_id = channel;
	hal_BOFFINT = &reg->ESR.R;
	hal_BOFFINT_T = *hal_BOFFINT;
    if (CAN_CUR_MODE_INIT == cand->state.cur_mode)
    {
        ControllerMode = CONTROLLERMODE_STARTED;
    }
    //else if (  (reg->ECR.B.TXECNT >= 128u))
    else if (  (can_busoff_flag == 1U ))
    //else if ( (CAN_CUR_MODE_FREEZE == cand->state.cur_mode) && (hal_BOFFINT == 1))
    {
        ControllerMode = CONTROLLERMODE_BUSOFF;
    }
    else if (CAN_CUR_MODE_NORMAL == cand->state.cur_mode)
    {
        ControllerMode = CONTROLLERMODE_STARTED;
    }else if (CAN_CUR_MODE_SLEEP == cand->state.cur_mode)
    {
        ControllerMode = CONTROLLERMODE_SLEEP;
    }
    else if (CAN_CUR_MODE_FREEZE == cand->state.cur_mode)
    {
        ControllerMode = CONTROLLERMODE_STOPPED;
    }else if (CAN_CUR_MODE_LISTEN_ONLY == cand->state.cur_mode)
    {
        ControllerMode = CONTROLLERMODE_STOPPED;
    }else if (CAN_CUR_MODE_LOOP_BACK == cand->state.cur_mode)
    {
        ControllerMode = CONTROLLERMODE_STOPPED;
    }
    else{
        ControllerMode = CONTROLLERMODE_UNINIT;
    }
    return ControllerMode;
}

/*
 * function description: Query the count value of CAN send error register
 * param: can_channel channel
 * return: uint8_t 
 * TODO:
*/
uint8_t hal_can_TEC(can_channel channel)
{
	config.can_id = channel;
    return reg->ECR.B.TXECNT;
}

/*
 * function description: Query the count value of the CAN acceptance error register
 * param: can_channel channel
 * return: uint8_t 
 * TODO:
*/
uint8_t hal_can_REC(can_channel channel)
{
	config.can_id = channel;
    return reg->ECR.B.RXECNT;
}


/*
 * function description: This function shall be copy data buffer.
 * param: uint8_t * dest, const uint8_t * src, uint32_t bytes
 * return: void
 * TODO:
*/
void hal_cc_memcpy(uint8_t * dest, const uint8_t * src, uint32_t bytes)
{
    uint32_t bytes_temp;
    uint8_t * dest_temp = NULL;
    uint8_t const * src_temp = NULL;

    bytes_temp = bytes;
    dest_temp = dest;
    src_temp = src;

      while (bytes_temp > 0u)
      {
          *dest_temp = *src_temp;
          bytes_temp--;
          if (0u == bytes_temp)
          {
              break;
          }
          dest_temp++;
          src_temp++;
      }
//   for (bytes_temp = bytes; bytes_temp <=0; bytes_temp--)
//   {
//       *dest_temp = *src_temp;
//       dest_temp++;
//       src_temp++;
//   }
    
}
/*
 * function description: Can interrupt configuration
 * param: can_channel\irq_type\INTC_CPR_t\can_enabled
 * return: void
 * TODO:
*/
void hal_can_irq_config(can_channel channel,irq_type irq,INTC_CPR_t priorty,can_enabled is_enable)
{
     /* enable interrupt */
    //Can_LLD_Init_Intr(reg, config);

    uint32_t idx, offset;
    uint32_t imrl = 0xFFFFFFFFU;
    uint32_t imrh = 0xFFFFFFFFU;
    uint32_t fifo_use_mb_num = Can_LLD_Get_FIFO_Use_MB_Num(&config);
    config.can_id = channel;
    /* hook callback */
    hal_cc_memcpy((uint8_t *)&g_intr_callback[config.can_id],
        (const uint8_t *)&config.call_back, sizeof(CANIntrCallback));
    switch (config.can_id)
    {
        case CAN_MOD_ID_0 :
        {
            for (idx = CAN_LLD_INTR_MSG_00_03_NUM(CAN_MOD_ID_0);
                idx <= CAN_LLD_INTR_MSG_32_63_NUM(CAN_MOD_ID_0); idx++)
            {
                INTC_InstallINTCInterruptHandler(CAN_LLD_INTR_MSG_HANDLER_NAME(CAN_MOD_ID_0),
                    (uint16_t)idx, priorty);
            }
            INTC_InstallINTCInterruptHandler(CAN_LLD_INTR_ERR_HANDLER_NAME(CAN_MOD_ID_0),
                CAN_LLD_INTR_ESR_ERROR_NUM(CAN_MOD_ID_0), CAN_FLEXCAN0_IRQ_PRIORITY);
            break;
        }
        case CAN_MOD_ID_1 :
        {
            for (idx = CAN_LLD_INTR_MSG_00_03_NUM(CAN_MOD_ID_1);
                idx <= CAN_LLD_INTR_MSG_32_63_NUM(CAN_MOD_ID_1); idx++)
            {
                INTC_InstallINTCInterruptHandler(CAN_LLD_INTR_MSG_HANDLER_NAME(CAN_MOD_ID_1),
                    (uint16_t)idx, CAN_FLEXCAN1_IRQ_PRIORITY);
            }
            INTC_InstallINTCInterruptHandler(CAN_LLD_INTR_ERR_HANDLER_NAME(CAN_MOD_ID_1),
                CAN_LLD_INTR_ESR_ERROR_NUM(CAN_MOD_ID_1), CAN_FLEXCAN0_IRQ_PRIORITY);
            break;
        }
        case CAN_MOD_ID_2 :
        {
            for (idx = CAN_LLD_INTR_MSG_00_03_NUM(CAN_MOD_ID_2);
                idx <= CAN_LLD_INTR_MSG_32_63_NUM(CAN_MOD_ID_2); idx++)
            {
                INTC_InstallINTCInterruptHandler(CAN_LLD_INTR_MSG_HANDLER_NAME(CAN_MOD_ID_2),
                    (uint16_t)idx, priorty);
            }
            INTC_InstallINTCInterruptHandler(CAN_LLD_INTR_ERR_HANDLER_NAME(CAN_MOD_ID_2),
                CAN_LLD_INTR_ESR_ERROR_NUM(CAN_MOD_ID_2), CAN_FLEXCAN0_IRQ_PRIORITY);
            break;
        }
        case CAN_MOD_ID_3 :
        {
            for (idx = CAN_LLD_INTR_MSG_00_03_NUM(CAN_MOD_ID_3);
                idx <= CAN_LLD_INTR_MSG_32_63_NUM(CAN_MOD_ID_3); idx++)
            {
                INTC_InstallINTCInterruptHandler(CAN_LLD_INTR_MSG_HANDLER_NAME(CAN_MOD_ID_3),
                    (uint16_t)idx, priorty);
            }
            INTC_InstallINTCInterruptHandler(CAN_LLD_INTR_ERR_HANDLER_NAME(CAN_MOD_ID_3),
                CAN_LLD_INTR_ESR_ERROR_NUM(CAN_MOD_ID_3), CAN_FLEXCAN0_IRQ_PRIORITY);
            break;
        }
        case CAN_MOD_ID_4 :
        {
            for (idx = CAN_LLD_INTR_MSG_00_03_NUM(CAN_MOD_ID_4);
                idx <= CAN_LLD_INTR_MSG_32_63_NUM(CAN_MOD_ID_4); idx++)
            {
                INTC_InstallINTCInterruptHandler(CAN_LLD_INTR_MSG_HANDLER_NAME(CAN_MOD_ID_4),
                    (uint16_t)idx, priorty);
            }
            INTC_InstallINTCInterruptHandler(CAN_LLD_INTR_ERR_HANDLER_NAME(CAN_MOD_ID_4),
                CAN_LLD_INTR_ESR_ERROR_NUM(CAN_MOD_ID_4), CAN_FLEXCAN0_IRQ_PRIORITY);
            break;
        }
        case CAN_MOD_ID_5 :
        {
            for (idx = CAN_LLD_INTR_MSG_00_03_NUM(CAN_MOD_ID_5);
                idx <= CAN_LLD_INTR_MSG_32_63_NUM(CAN_MOD_ID_5); idx++)
            {
                INTC_InstallINTCInterruptHandler(CAN_LLD_INTR_MSG_HANDLER_NAME(CAN_MOD_ID_5),
                    (uint16_t)idx, priorty);
            }
            INTC_InstallINTCInterruptHandler(CAN_LLD_INTR_ERR_HANDLER_NAME(CAN_MOD_ID_5),
                CAN_LLD_INTR_ESR_ERROR_NUM(CAN_MOD_ID_5), CAN_FLEXCAN0_IRQ_PRIORITY);
            break;
        }
        default :
        {
            break;
        }
    }

    /* enable interrupt */
    if (config.call_back.rx_fifo_msg_received == NULL)
    {
        for (idx = 0; idx < fifo_use_mb_num; idx++)
        {
            offset = idx;
            BIT_CLR(imrl, offset); /* PRQA S 3335, 3473 # simple macro function */
        }
    }
    if (config.call_back.rx_mb_msg_received == NULL)
    {
        for (idx = fifo_use_mb_num;
            idx < (fifo_use_mb_num + config.buf_cfg.rx_mb_num); idx++)
        {
            if (idx < CAN_WORD_INDICATE_MAIL_BOX_NUM)
            {
                offset = idx;
                BIT_CLR(imrl, offset); /* PRQA S 3335, 3473 # simple macro function */
            }
            else
            {
                offset = idx - CAN_WORD_INDICATE_MAIL_BOX_NUM;
                BIT_CLR(imrh, offset); /* PRQA S 3335, 3473 # simple macro function */
            }
        }
    }

    /* enable interrupt */
    reg->IMRL.R = imrl;
    reg->IMRH.R = imrh;
    reg->MCR.B.WRNEN = is_enable; /* Warning */
    reg->CR.B.TWRNMSK = is_enable; /* Tx Warning */
    reg->CR.B.BOFFMSK = CAN_DISABLE; /* Bus Off */
    reg->CR.B.RWRNMSK = CAN_DISABLE; /* Rx Warning */
    if (IRQ_TYPE_RX == irq)
    {
        reg->CR.B.RWRNMSK = is_enable; /* Rx Warning */
    }else if (IRQ_TYPE_BUSOFF == irq)
    {
        reg->CR.B.BOFFMSK = is_enable; /* Bus Off */
    }else if (IRQ_TYPE_RX_BUSOFF == irq)
    {
        reg->CR.B.RWRNMSK = is_enable; /* Rx Warning */
        reg->CR.B.BOFFMSK = is_enable; /* Bus Off */
    }else{}
    reg->CR.B.ERRMSK = is_enable; /* Error */
}

/*
 * function description: CAN enable interrupt
 * param: can_channel\irq_type\can_enabled
 * return: void
 * TODO:
*/
void hal_can_irq_enabled(can_channel channel,irq_type irq,can_enabled is_enable)
{
	config.can_id = channel;
    /* enable interrupt */
    reg->MCR.B.WRNEN = is_enable; /* Warning */
    reg->CR.B.TWRNMSK = is_enable; /* Tx Warning */
    reg->CR.B.BOFFMSK = CAN_DISABLE; /* Bus Off */
    reg->CR.B.RWRNMSK = CAN_DISABLE; /* Rx Warning */
    if (IRQ_TYPE_RX == irq)
    {
        reg->CR.B.RWRNMSK = is_enable; /* Rx Warning */
    }else if (IRQ_TYPE_BUSOFF == irq)
    {
        reg->CR.B.BOFFMSK = is_enable; /* Bus Off */
    }else if (IRQ_TYPE_RX_BUSOFF == irq)
    {
        reg->CR.B.RWRNMSK = is_enable; /* Rx Warning */
        reg->CR.B.BOFFMSK = is_enable; /* Bus Off */
    }else{}
    reg->CR.B.ERRMSK = is_enable; /* Error */
}

/*
 * function description: CAN Test interface functions
 * param: void
 * return: void
 * TODO:
*/
void hal_can_init_test(void)
{
    //CANRxMsg rx_msg;
    pdu_str pdu;
    str  hal_strtest;
    uint8_t get_ctrl_mode = 0;
    uint8_t byte[8] = {0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55};
    filter_struct can_filter_array[1];
    *(pdu.buff) = byte;
    pdu.DLC = 8u;
    pdu.ID = 0x60A;
    hal_strtest.arbitr = CANHAL_KBPS_500;
    hal_strtest.canenabled = CAN_ENABLE;
    can_filter_array[0].id_type = ID_TYPE_STAND;
    can_filter_array[0].filter_code = 0x60A;
    can_filter_array[0].filter_mask = 0xffffffffU;
    hal_can_init(CAN_CHANNEL0,&hal_strtest);
	// hal_can_enabled(CAN_CHANNEL1,CAN_ENABLE);
	// hal_can_baudrate(CAN_CHANNEL1,CAN_KBPS_500);
    //hal_can_filter_config(CAN_CHANNEL1,can_filter_array,1);
    hal_can_filter_config(CAN_CHANNEL0,can_filter_array,3);
    hal_can_trcv_mode(CAN_CHANNEL0,HAL_CAN_TRCV_MODE_NORMAL);
    //hal_can_irq_config(CAN_CHANNEL1,IRQ_TYPE_RX_BUSOFF,CPR_PRI_11,CAN_ENABLE);
    //hal_can_write(CAN_CHANNEL0,&pdu);
    #if 0
    hal_can_trcv_mode(CAN_CHANNEL0,HAL_CAN_TRCV_MODE_STANDBY);
    get_ctrl_mode = hal_can_get_trcv_mode(CAN_CHANNEL0);
    // hal_can_read(CAN_CHANNEL1,&rx_msg);
    // get_ctrl_mode = hal_can_get_ctrl_mode(CAN_CHANNEL1);
    // hal_can_ctrl_mode(CAN_CHANNEL1,CONTROLLERMODE_STOPPED);
    // get_ctrl_mode = hal_can_get_ctrl_mode(CAN_CHANNEL1);
    // hal_can_ctrl_mode(CAN_CHANNEL1,CONTROLLERMODE_STARTED);
    // get_ctrl_mode = hal_can_get_ctrl_mode(CAN_CHANNEL1);
    // hal_can_ctrl_mode(CAN_CHANNEL1,CONTROLLERMODE_SLEEP);
    // get_ctrl_mode = hal_can_get_ctrl_mode(CAN_CHANNEL1);
    // hal_can_ctrl_mode(CAN_CHANNEL1,CONTROLLERMODE_STARTED);
    // get_ctrl_mode = hal_can_get_ctrl_mode(CAN_CHANNEL1);
    // hal_can_ctrl_mode(CAN_CHANNEL1,CONTROLLERMODE_BUSOFF);
    // get_ctrl_mode = hal_can_get_ctrl_mode(CAN_CHANNEL1);
    // get_ctrl_mode = hal_can_TEC(CAN_CHANNEL1);
    #endif
}
